package cjzq

import (
	"fmt"
	"log"
	"strconv"
	"strings"
	"sync"
	"syscall"
	"time"

	"gitee.com/lilihli/connector/winapi"
	"github.com/lxn/win"
)

// CjzqWnd 独立下单主窗口信息
type CjzqWnd struct {
	hwnd    win.HWND
	workWnd *WorkWnd
}

// NewCjzqWnd new CjzqWnd
func NewCjzqWnd() *CjzqWnd {
	this := &CjzqWnd{}
	this.workWnd = NewWorkWnd()
	return this
}

// UpdateWindowHandle 更新窗口句柄
func (cjzqWnd *CjzqWnd) UpdateWindowHandle() error {
	hwnd := win.FindWindow(syscall.StringToUTF16Ptr("TdxW_MainFrame_Class"), nil)
	if hwnd == 0 {
		return fmt.Errorf("未找到下单软件窗口，请确认下单软件已启动")
	}
	//如果本窗口不在前台，将窗口设置到前台
	foreWnd := win.GetForegroundWindow()
	if foreWnd != hwnd {
		//想要SetForegroundWindow生效，必须得是前置的进程（活动的进程）
		dwCurID := win.GetCurrentThreadId()
		dwForeID := win.GetWindowThreadProcessId(foreWnd, nil)
		win.AttachThreadInput(int32(dwCurID), int32(dwForeID), true)
		win.SetForegroundWindow(hwnd)
		win.BringWindowToTop(hwnd)
		win.AttachThreadInput(int32(dwCurID), int32(dwForeID), false)
		time.Sleep(time.Second) //设置到前台需要等待一秒钟，让窗口切换
	}

	// win.SetWindowPos(hwnd, win.HWND_TOP, 0, 0, 0, 0, win.SWP_NOSIZE | win.SWP_NOMOVE);
	cjzqWnd.hwnd = hwnd
	cjzqWnd.workWnd.SetParentWnd(hwnd)
	err := cjzqWnd.workWnd.UpdateWindowHandle()
	if err != nil {
		return fmt.Errorf("cjzqWnd.workWnd.UpdateWindowHandle failed, %v", err)
	}
	return nil
}

// CloseUnimportancePopWindow 关闭不重要的弹出窗口
func (cjzqWnd *CjzqWnd) CloseUnimportancePopWindow() {
	CloseUnimportancePopWindow(cjzqWnd.hwnd)
}

// WorkWnd 工作区域窗口
type WorkWnd struct {
	parent  win.HWND
	hwnd    win.HWND
	navWnd  *NavWnd //左面的tab切换窗口
	mscWnd  *MSCWnd //右边窗口上面一栏，有买入、卖出、撤单、成交、持仓、刷新等按钮
	buyWnd  *BuyWnd
	saleWnd *SaleWnd
	// cancelWnd *CancelWnd
	// queryWnd  *QueryWnd
}

// NewWorkWnd new WorkWnd
func NewWorkWnd() *WorkWnd {
	this := &WorkWnd{}
	this.navWnd = NewNavWnd()
	this.mscWnd = NewMSCWnd()
	this.buyWnd = NewBuyWnd()
	this.saleWnd = NewSaleWnd()
	// this.cancelWnd = NewCancelWnd()
	// this.queryWnd = NewQueryWnd()
	return this
}

// SetParentWnd 设置父窗口句柄
func (workWnd *WorkWnd) SetParentWnd(parentWnd win.HWND) {
	workWnd.parent = parentWnd
}

// UpdateWindowHandle 更新窗口句柄
func (workWnd *WorkWnd) UpdateWindowHandle() error {
	hwnd := winapi.FindClildWindow(workWnd.parent, "AfxMDIFrame42", "")
	if hwnd == 0 {
		return fmt.Errorf("未找到工作窗口")
	}
	workWnd.hwnd = hwnd

	workWnd.navWnd.SetParentWnd(hwnd)
	workWnd.mscWnd.SetParentWnd(hwnd)
	workWnd.buyWnd.SetParentWnd(hwnd)
	workWnd.saleWnd.SetParentWnd(hwnd)

	err := workWnd.navWnd.UpdateWindowHandle()
	if err != nil {
		return fmt.Errorf("workWnd.navWnd.UpdateWindowHandle failed, %v", err)
	}

	err = workWnd.mscWnd.UpdateWindowHandle()
	if err != nil {
		return fmt.Errorf("workWnd.mscWnd.UpdateWindowHandle failed, %v", err)
	}

	//没有初始化的窗口进行初始化
	if workWnd.buyWnd.FindSelf() == 0 {
		workWnd.mscWnd.ShowBuyWnd()
		time.Sleep(time.Millisecond * 500)
	}
	if workWnd.saleWnd.FindSelf() == 0 {
		workWnd.mscWnd.ShowSaleWnd()
		time.Sleep(time.Millisecond * 500)
	}

	err = workWnd.buyWnd.UpdateWindowHandle()
	if err != nil {
		return fmt.Errorf("workWnd.buyWnd.UpdateWindowHandle failed, %v", err)
	}

	err = workWnd.saleWnd.UpdateWindowHandle()
	if err != nil {
		return fmt.Errorf("workWnd.saleWnd.UpdateWindowHandle failed, %v", err)
	}

	// workWnd.mscWnd.ShowBuyWnd()
	// time.Sleep(time.Millisecond * 500)
	// err = workWnd.buyWnd.FillStockCode("000651")
	// fmt.Println(err)
	// price, err := workWnd.buyWnd.LoopGetPrice()
	// fmt.Println(price, err)
	// time.Sleep(time.Millisecond * 10)
	// err = workWnd.buyWnd.FillAmount(100)
	// fmt.Println(err)

	return nil
}

type MSCWnd struct {
	parent win.HWND
	hwnd   win.HWND
}

func NewMSCWnd() *MSCWnd {
	this := &MSCWnd{}
	return this
}

// SetParentWnd 设置父窗口句柄
func (mscWnd *MSCWnd) SetParentWnd(parentWnd win.HWND) {
	mscWnd.parent = parentWnd
}

// UpdateWindowHandle 更新窗口句柄
func (mscWnd *MSCWnd) UpdateWindowHandle() error {
	hwnd := winapi.FindClildWindow(mscWnd.parent, "MHPToolBar", "MainViewBar")
	if hwnd == 0 {
		return fmt.Errorf("未找到窗口")
	}
	mscWnd.hwnd = hwnd
	return nil
}

func (mscWnd *MSCWnd) ShowBuyWnd() {
	lParam := uint32(0xf0014)
	win.PostMessage(mscWnd.hwnd, win.WM_LBUTTONDOWN, 0, uintptr(lParam))
	time.Sleep(time.Millisecond * 100)
	win.PostMessage(mscWnd.hwnd, win.WM_LBUTTONUP, 0, uintptr(lParam))
}

func (mscWnd *MSCWnd) ShowSaleWnd() {
	lParam := uint32(0xf0036)
	win.PostMessage(mscWnd.hwnd, win.WM_LBUTTONDOWN, 0, uintptr(lParam))
	time.Sleep(time.Millisecond * 100)
	win.PostMessage(mscWnd.hwnd, win.WM_LBUTTONUP, 0, uintptr(lParam))
}

// NavWnd 左侧导航窗口
type NavWnd struct {
	parent win.HWND
	tab    win.HWND
}

func NewNavWnd() *NavWnd {
	this := &NavWnd{}
	return this
}

// SetParentWnd 设置父窗口句柄
func (navWnd *NavWnd) SetParentWnd(parentWnd win.HWND) {
	navWnd.parent = parentWnd
}

// UpdateWindowHandle 更新窗口句柄
func (navWnd *NavWnd) UpdateWindowHandle() error {
	hwnd1 := win.GetDlgItem(navWnd.parent, 0xe900)
	if hwnd1 == 0 {
		return fmt.Errorf("未找到窗口1")
	}
	hwnd2 := win.GetDlgItem(hwnd1, 0xdd)
	if hwnd2 == 0 {
		return fmt.Errorf("未找到窗口2")
	}
	navWnd.tab = hwnd2
	//将导航页切换到股票债券界面
	for i := 0; i < 5; i++ {
		if navWnd.IsStockWnd() {
			break
		}
		lParam := uint32(0x50005)
		win.SendMessage(hwnd2, win.WM_LBUTTONDOWN, 0, uintptr(lParam))
		win.SendMessage(hwnd2, win.WM_LBUTTONUP, 0, uintptr(lParam))
	}
	return nil
}

// 判断导航栏当前是否是股票债券交易界面
func (navWnd *NavWnd) IsStockWnd() bool {
	var b [6]bool
	for i := int32(0); i < 6; i++ {
		hwnd3 := win.GetDlgItem(navWnd.tab, 0xe900+i)
		b[i] = win.IsWindowVisible(hwnd3)
	}
	return b[0] && !b[1] && !b[2] && !b[3] && !b[4] && !b[5]
}

// BaseWnd 右侧区域窗口基类
type BaseWnd struct {
	name   string //ctrlID 控件的标题
	ctrlID int32  //该窗口中的某个控件的ID，用来识别是否该窗口
	// hotKey uint32 //热键，买入为 win.VK_F1, 卖出为 win.VK_F2
	parent win.HWND
}

// SetParentWnd 设置父窗口句柄
func (baseWnd *BaseWnd) SetParentWnd(parentWnd win.HWND) {
	baseWnd.parent = parentWnd
}

// FindSelf 从父窗口中找到自己
func (baseWnd *BaseWnd) FindSelf() win.HWND {
	return winapi.FindChildWindowHasCtrl(baseWnd.parent, baseWnd.ctrlID, baseWnd.name)
}

// BuySaleWnd 买入股票窗口
type BuySaleWnd struct {
	BaseWnd
	hwnd win.HWND //买入页面的窗口句柄
}

// UpdateWindowHandle 更新窗口句柄
func (buySaleWnd *BuySaleWnd) UpdateWindowHandle() error {
	hwnd := buySaleWnd.FindSelf()
	if hwnd == 0 {
		return fmt.Errorf("未找到 %s 窗口,ctrlID=%x", buySaleWnd.name, buySaleWnd.ctrlID)
	}
	buySaleWnd.hwnd = hwnd
	return nil
}

// FillStockCode 填充证券代码输入框,此处需要使用模拟按键的方式
func (buySaleWnd *BuySaleWnd) FillStockCode(code string) error {
	ctrlWnd := winapi.FindClildWindow(buySaleWnd.hwnd, "AfxWnd42", "")
	if ctrlWnd == 0 {
		return fmt.Errorf("没有找到证券代码输入框")
	}

	buf := []byte(code)
	for _, b := range buf {
		b2, err := winapi.VkKeyScan(b)
		if err != nil {
			return fmt.Errorf("winapi.VkKeyScan failed, %v", err)
		}
		wParam := b2 & 0xff
		b3, err := winapi.MapVirtualKey(uint32(wParam), 0)
		if err != nil {
			return fmt.Errorf("winapi.VkKeyScan failed, %v", err)
		}
		lParam := (b3 + 1) << 16
		win.PostMessage(ctrlWnd, win.WM_KEYDOWN, uintptr(wParam), uintptr(lParam))
		lParam += 1 << 30
		lParam += 1 << 31
		time.Sleep(time.Millisecond * 50)
		win.PostMessage(ctrlWnd, win.WM_KEYUP, uintptr(wParam), uintptr(lParam))
		time.Sleep(time.Millisecond * 50)
	}
	return nil
}
func (buySaleWnd *BuySaleWnd) LoopGetPrice() (price float64, err error) {
	for i := 0; i < 20; i++ {
		price, err = buySaleWnd.GetPrice()
		if err == nil {
			return price, nil
		}
		time.Sleep(time.Millisecond * 10)
	}
	return 0, err
}

// GetPrice 填充买入价格输入框
func (buySaleWnd *BuySaleWnd) GetPrice() (float64, error) {
	str, err := winapi.GetDlgItemText(buySaleWnd.hwnd, 0x2ee6)
	if err != nil {
		return 0, fmt.Errorf("winapi.GetDlgItemText failed, %v", err)
	}
	price, err := strconv.ParseFloat(str, 64)
	if err != nil {
		return 0, fmt.Errorf("strconv.ParseFloat failed, %v", err)
	}
	return price, nil
}

// FillAmount 填充买入数量输入框
func (buySaleWnd *BuySaleWnd) FillAmount(amount uint64) error {
	err := winapi.SetDlgItemText(buySaleWnd.hwnd, 0x2ee7, strconv.FormatUint(amount, 10))
	if err != nil {
		return fmt.Errorf("winapi.SetDlgItemText failed, %v", err)
	}
	return nil
}

// 得到最顶层父窗口
func getTopParentWnd(hwnd win.HWND) win.HWND {
	for {
		p := win.GetParent(hwnd)
		if p == 0 {
			break
		}
		hwnd = p
	}
	return hwnd
}

func (buySaleWnd *BuySaleWnd) transactionConfirmation(wnd win.HWND) error {
	topWnd := getTopParentWnd(wnd)
	if topWnd == 0 {
		return fmt.Errorf("未找到顶层窗口")
	}
	for i := 0; ; i++ {
		time.Sleep(time.Millisecond * 100)
		var delegationWnd win.HWND
		if buySaleWnd.name == "买入下单" {
			delegationWnd = win.FindWindow(nil, syscall.StringToUTF16Ptr("买入交易确认"))
		} else if buySaleWnd.name == "卖出下单" {
			delegationWnd = win.FindWindow(nil, syscall.StringToUTF16Ptr("卖出交易确认"))
		} else {
			panic("buySaleWnd.name error")
		}
		if delegationWnd != 0 {
			//判断委托确认窗口的父窗口和顶层窗口是否一致
			phwnd := win.GetParent(delegationWnd)
			if topWnd != phwnd {
				break
			}

			//获取 确认(Y) 按钮
			okBtnWnd := win.GetDlgItem(delegationWnd, 0x1b67)
			if okBtnWnd == 0 {
				return fmt.Errorf("没有找到确认窗口中的 确认 按钮")
			}
			win.SendMessage(okBtnWnd, win.WM_LBUTTONDOWN, 0, 0)
			win.SendMessage(okBtnWnd, win.WM_LBUTTONUP, 0, 0)
			break
		}

		if i > 10 {
			return fmt.Errorf(`未找到 %s 交易确认窗口，请确认下单软件已启动`, buySaleWnd.name)
		}
	}
	return nil
}

// BuySale 买卖，买入窗口则是买入，卖出窗口则是卖出
func (buySaleWnd *BuySaleWnd) BuySale(code string, price float64, amount uint64) (int, error) {
	//关闭不重要的弹出窗口,以免影响委托确认窗口和结果窗口内容的获取
	topWnd := win.GetParent(buySaleWnd.parent)
	CloseUnimportancePopWindow(topWnd)

	err := buySaleWnd.FillAmount(amount)
	if err != nil {
		return 0, fmt.Errorf("buySaleWnd.FillAmount failed, %v", err)
	}
	hwnd := win.GetDlgItem(buySaleWnd.hwnd, 0x7da)
	if hwnd == 0 {
		return 0, fmt.Errorf("没有找到 %s 的按钮", buySaleWnd.name)
	}
	var wg sync.WaitGroup
	wg.Add(1)
	go func() {
		//检查弹出的交易确认框，点击确认按钮
		err = buySaleWnd.transactionConfirmation(topWnd)
		if err != nil {
			log.Printf("buySaleWnd.transactionConfirmation failed, %v", err)
		}
		wg.Done()
	}()

	//点击买入、卖出按钮
	win.SendMessage(hwnd, win.WM_LBUTTONDOWN, 0, 0)
	win.SendMessage(hwnd, win.WM_LBUTTONUP, 0, 0)

	wg.Wait()

	time.Sleep(time.Second)
	ContractNo := 0
	for i := 0; ; i++ {
		time.Sleep(time.Millisecond * 100)
		resultWnd := win.GetWindow(getTopParentWnd(topWnd), win.GW_ENABLEDPOPUP)
		if resultWnd != 0 {
			text, err := winapi.GetDlgItemText(resultWnd, 0x1B65)
			if err != nil {
				return 0, fmt.Errorf("获取窗口标题失败, %v", err)
			}
			if !strings.Contains(text, "委托已提交,合同号是") {
				return 0, fmt.Errorf(`获取委托结果窗口中 合同编号 失败, 窗口提示信息："%s"`, text)
			}

			text = strings.ReplaceAll(text, "委托已提交,合同号是", "")
			num, err := strconv.Atoi(text)
			if err != nil {
				return 0, fmt.Errorf("获取委托结果窗口中 合同编号 失败, strconv.Atoi %s, %v", text, err)
			}
			ContractNo = num

			text, err = winapi.GetDlgItemText(resultWnd, 0x1b67)
			if err != nil {
				return 0, fmt.Errorf("获取委托结果窗口中 确认 按钮的文字失败, %v", err)
			}
			if text != "确认" {
				return 0, fmt.Errorf("委托结果窗口中的 确认 按钮的文字不正确")
			}

			okBtnWnd := win.GetDlgItem(resultWnd, 0x1b67)
			if okBtnWnd == 0 {
				return 0, fmt.Errorf("没有找到委托结果窗口中的 确认 按钮")
			}
			win.SendMessage(okBtnWnd, win.WM_LBUTTONDOWN, 0, 0)
			win.SendMessage(okBtnWnd, win.WM_LBUTTONUP, 0, 0)
			break
		}
		if i > 50 {
			return 0, fmt.Errorf("没有找到委托结果窗口")
		}
	}
	return ContractNo, nil
}

// BuyWnd 买入窗口
type BuyWnd struct {
	BuySaleWnd
}

// NewBuyWnd new BuyWnd
func NewBuyWnd() *BuyWnd {
	this := &BuyWnd{}
	this.name = "买入下单"
	this.ctrlID = 0x7da
	return this
}

// Buy 买入
func (buyWnd *BuyWnd) Buy(code string, price float64, amount uint64) (int, error) {
	return buyWnd.BuySale(code, price, amount)
}

// SaleWnd 卖出窗口
type SaleWnd struct {
	BuySaleWnd
}

// NewSaleWnd new SaleWnd
func NewSaleWnd() *SaleWnd {
	this := &SaleWnd{}
	this.name = "卖出下单"
	this.ctrlID = 0x7da
	return this
}

// Sale 卖出
func (saleWnd *SaleWnd) Sale(code string, price float64, amount uint64) (int, error) {
	return saleWnd.BuySale(code, price, amount)
}

// CancelWnd 撤单页面
type CancelWnd struct {
	BaseWnd
	hwnd win.HWND
}

// NewCancelWnd new CancelWnd
func NewCancelWnd() *CancelWnd {
	this := &CancelWnd{}
	this.name = "撤单"
	this.ctrlID = 0x44b
	return this
}

// UpdateWindowHandle 更新窗口句柄
func (cancelWnd *CancelWnd) UpdateWindowHandle() error {
	hwnd := cancelWnd.FindSelf()
	if hwnd == 0 {
		return fmt.Errorf("未找到撤单窗口")
	}
	cancelWnd.hwnd = hwnd
	return nil
}

// Cancel 撤单
func (cancelWnd *CancelWnd) Cancel() {

}

// QueryWnd 撤单页面
type QueryWnd struct {
	BaseWnd
	hwnd win.HWND
}

// NewQueryWnd new QueryWnd
func NewQueryWnd() *QueryWnd {
	this := &QueryWnd{}
	this.name = "查询资金股票"
	this.ctrlID = 0x5c6
	return this
}

// UpdateWindowHandle 更新窗口句柄
func (queryWnd *QueryWnd) UpdateWindowHandle() error {
	hwnd := queryWnd.FindSelf()
	if hwnd == 0 {
		return fmt.Errorf("未找到查询资金股票窗口")
	}
	queryWnd.hwnd = hwnd
	return nil
}

// QueryWndInfo 查询窗口信息
type QueryWndInfo struct {
	FundBalance        float64 //资金余额
	WithdrawableAmount float64 //可取金额
	LockAmount         float64 //冻结金额
	StockMarketValue   float64 //股票市值
	AvailableAmount    float64 //可用金额
	TotalAssets        float64 //总资产
	CashAssets         float64 //现金资产
}

// Info 获取信息
func (queryWnd *QueryWnd) Info() (*QueryWndInfo, error) {
	var info QueryWndInfo
	list := []struct {
		CtrlID int32
		ErrWnd error
		Value  *float64
	}{
		{
			CtrlID: 0x3f4,
			ErrWnd: fmt.Errorf("没有找到资金余额窗口"),
			Value:  &info.FundBalance,
		}, {
			CtrlID: 0x3f9,
			ErrWnd: fmt.Errorf("没有找到可取金额窗口"),
			Value:  &info.WithdrawableAmount,
		}, {
			CtrlID: 0x3f5,
			ErrWnd: fmt.Errorf("没有找到冻结金额窗口"),
			Value:  &info.LockAmount,
		}, {
			CtrlID: 0x3f6,
			ErrWnd: fmt.Errorf("没有找到股票市值窗口"),
			Value:  &info.StockMarketValue,
		}, {
			CtrlID: 0x3f8,
			ErrWnd: fmt.Errorf("没有找到可用金额窗口"),
			Value:  &info.AvailableAmount,
		}, {
			CtrlID: 0x3f7,
			ErrWnd: fmt.Errorf("没有找到总资产窗口"),
			Value:  &info.TotalAssets,
		}, {
			CtrlID: 0x5cb,
			ErrWnd: fmt.Errorf("没有找到现金资产窗口"),
			Value:  &info.CashAssets,
		},
	}
	for _, item := range list {
		hwnd := win.GetDlgItem(queryWnd.hwnd, item.CtrlID)
		if hwnd == 0 {
			return nil, item.ErrWnd
		}

		str := winapi.GetWindowText(hwnd)
		value, err := strconv.ParseFloat(str, 64)
		if err != nil {
			return nil, fmt.Errorf("strconv.ParseFloat %s failed, %v", str, err)
		}
		*item.Value = value
	}
	// buf, _ := json.Marshal(&info)
	// fmt.Println(string(buf))
	return &info, nil
}

// CloseUnimportancePopWindow 关闭不重要的弹出窗口
func CloseUnimportancePopWindow(hwnd win.HWND) {
	// winapi.EnumPopupWindow(hwnd, func(popup win.HWND) {
	// 	// fmt.Printf("popup: %x\n", popup)
	// 	title, err := winapi.GetDlgItemText(popup, 0x555)
	// 	if err == nil {
	// 		if title == "安全信息及设置" {
	// 			fmt.Printf("安全信息及设置窗口 关闭\n")
	// 			win.PostMessage(popup, win.WM_CLOSE, 0, 0)
	// 			time.Sleep(time.Second)
	// 		} else if title == "营业部公告" {
	// 			fmt.Printf("营业部公告窗口 关闭\n")
	// 			win.PostMessage(popup, win.WM_CLOSE, 0, 0)
	// 			time.Sleep(time.Second)
	// 		}
	// 	}
	// })
}
